#ifndef DB_HPP
#define DB_HPP
#include "util.hpp"

class user_table
{
private:
    MYSQL *_mysql;
    std::mutex _mutex;

public:
    user_table(
        const std::string &host,
        const std::string &username,
        const std::string &password,
        const std::string &dbname,
        const unsigned int port = 3306)
    {
        _mysql = mysql_util::mysql_create(host, username, password, dbname, port);
        if (_mysql == NULL)
        {
            ELOG("mysql create failed");
            exit(0);
        }
    }
    ~user_table()
    {
        mysql_util::mysql_destroy(_mysql);
        _mysql = NULL;
        ELOG("mysql destroy");
    }
    bool insert(Json::Value &user)
    {
        // 先判断用户是否已经存在
        // Json::Value val;
        // bool ret = select_by_name(user["username"].asString(), val);
        // if (ret == true)
        // {
        //     DLOG("user %s already exists", user["username"].asString().c_str());
        //     return false;
        // }
        // 注意先判断用户是否存在这一步可以省略,前提是数据库中有唯一性约束

        // 2.如果存在,就返回用户信息
        if (user["username"].isNull() || user["password"].isNull())
        {
            ELOG("username or password is empty");
            return false;
        }
#define INSERT_USER "insert into user values(null,'%s',SHA2('%s',256),1000,0,0);"
        char sql[4096] = {0};
        sprintf(sql, INSERT_USER,
                user["username"].asString().c_str(),
                user["password"].asString().c_str());

        bool ret = mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            ELOG("insert user failed");
            return false;
        }
        return true;
    }

    bool login(Json::Value &user)
    {
        // 根据用户名和密码查询用户
        // 1.先查询用户是否存在
        // 获取用户
#define SELECT_USER "select id,score,total_count,win_count from user where username='%s' and password=SHA2('%s',256);"

        if (user["username"].isNull() || user["password"].isNull())
        {
            ELOG("username or password is empty");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql, SELECT_USER,
                user["username"].asString().c_str(),
                user["password"].asString().c_str());
        ILOG("username:%s,password:%s", user["username"].asString().c_str(), user["password"].asString().c_str());
        ILOG("sql:%s", sql);
        MYSQL_RES *res = NULL;
        {
            // 锁管理器,只要离开了域范围,就会自动解锁
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                ELOG("user login failed");

                return false;
            }
            // 获取结果集
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                ELOG("mysql store result failed");

                return false;
            }
        }

        // 结果有且只能只有一条
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            DLOG("user %s is not unique!", user["username"].asString().c_str());
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = std::stoi(row[0]);
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        ELOG("user %s login success", user["username"].asString().c_str());
        return true;
    }
    bool select_by_name(const std::string &name, Json::Value &user)
    {
#define SELECT_USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql, SELECT_USER_BY_NAME,
                name.c_str()); // 此处应该是参数的name,而不是uesr中的username

        bool ret = mysql_util::mysql_exec(_mysql, sql);

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (ret == false)
            {
                ELOG("select user by name failed");
                return false;
            }
            // 获取结果集
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                ELOG("mysql store result failed");
                return false;
            }
        }

        // 结果有且只能只有一条
        int row_num = mysql_num_rows(res);

        if (row_num > 1)
        {
            DLOG("user %s is not unique!", name.c_str());
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = std::stoi(row[0]);
        user["username"] = name;
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
    bool select_by_id(int id, Json::Value &user)
    {
#define SELECT_USER_BY_ID "select username,score,total_count,win_count from user where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, SELECT_USER_BY_ID,
                id);
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);

            if (ret == false)
            {
                ELOG("select user by id failed");
                return false;
            }
            // 获取结果集
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                ELOG("mysql store result failed");
                return false;
            }
        }
        // 结果有且只能只有一条
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            DLOG("user %d is not unique!", id);
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = id;
        user["username"] = row[0];
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
    // 胜利之后,更新用户信息
    bool win(int id)
    {
// 胜利时,天体分数+30,战斗场次+1,胜利场次+1
#define UPDATE_USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, UPDATE_USER_WIN,
                id);

        bool ret = mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            ELOG("update user win failed");
            return false;
        }
        return true;
    }
    // 失败之后,战斗场次+1,天体分数-30
    bool lose(int id)
    {
#define UPDATE_USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%d;"
        char sql[4096] = {0};
        sprintf(sql, UPDATE_USER_LOSE,
                id);

        bool ret = mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            ELOG("update user lose failed");
            return false;
        }
        return true;
    }
};
#endif